﻿using Blog.Entity.Domain;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
using System.Linq.Expressions;

namespace Blog.EntityFrameWork.EntityFramework.Repositories
{
    public abstract class BlogRepositoryBase<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey>
        where TEntity : class, IEntity<TPrimaryKey>
    {
        private BlogDbContext _blogDbContext;

        public BlogRepositoryBase(BlogDbContext blogDbContext)
        {
            _blogDbContext = blogDbContext;
        }

        #region 查询

        public virtual IQueryable<TEntity> GetAll()
        {
            return _blogDbContext.Set<TEntity>().AsQueryable();
        }

        public virtual async Task<List<TEntity>> GetAllListAsync()
        {
            return await _blogDbContext.Set<TEntity>().ToListAsync();
        }

        public virtual async Task<TEntity> FirstOrDefultAsync(Expression<Func<TEntity, bool>> expression)
        {
            return await GetAll().FirstOrDefaultAsync(expression);
        }

        public virtual async Task<TEntity> FirstOrDefultAsync(TPrimaryKey primaryKey)
        {
            return await GetAll().FirstOrDefaultAsync(CreateEqualityExpressionForId(primaryKey));
        }

        public virtual IQueryable<TEntity> Query(Expression<Func<TEntity,bool>> expression)
        {
            return _blogDbContext.Set<TEntity>().Where(expression).AsQueryable();
        }

        #endregion

        #region 新增

        public virtual async Task<TPrimaryKey> CreateAndGetIdAsync(TEntity entity)
        {
            var en = await _blogDbContext.Set<TEntity>().AddAsync(entity);
            await _blogDbContext.SaveChangesAsync();
            return en.Entity.Id;
        }

        #endregion

        #region 删除

        public virtual async Task Remove(TEntity entity)
        {
            _blogDbContext.Set<TEntity>().Remove(entity);
            await _blogDbContext.SaveChangesAsync();
        }

        public virtual async Task Remove(Expression<Func<TEntity,bool>> expression)
        {
            var query = Query(expression);
            foreach (var item in query)
            {
                _blogDbContext.Set<TEntity>().Remove(item);
            }
            await _blogDbContext.SaveChangesAsync();
        }

        #endregion

        #region 修改

        public virtual Task<TEntity> UpdateAsync(TEntity entity)
        {
            var en = _blogDbContext.Set<TEntity>().Update(entity);
            return Task.FromResult(en.Entity);
        }

        public virtual async Task<TEntity> UpdateAsync(TPrimaryKey key , Func<TEntity, Task> updateAction)
        {
            var en = await GetAll().FirstOrDefaultAsync(CreateEqualityExpressionForId(key));
            await updateAction(en);
            return en;
        }

        #endregion


        protected static Expression<Func<TEntity, bool>> CreateEqualityExpressionForId(TPrimaryKey id)
        {
            var lambdaParam = Expression.Parameter(typeof(TEntity));

            var lambdaBody = Expression.Equal(
                Expression.PropertyOrField(lambdaParam, "Id"),
                Expression.Constant(id, typeof(TPrimaryKey))
                );

            return Expression.Lambda<Func<TEntity, bool>>(lambdaBody, lambdaParam);
        }
    }
}
